import { V1EnvFromSource, V1Volume, V1VolumeMount } from "@kubernetes/client-node"
import * as crypto from 'crypto'
import { ExecuteContext, PlanContext } from "../../../packages/types"
import { ApplicationSecret, Configuration } from "../types"

export type ConfType = 'configMap' | 'secret'

export const patchVolumeAndEnv = (ctx: ExecuteContext, item: Configuration | ApplicationSecret, plan: PlanContext, cfgName: string, type: ConfType): void => {
  const workload = plan.data.workloadName
  const containers = item.container ? [item.container] : item.containers ? item.containers : [plan.data.app]
  if (item.asEnv) {
    containers.forEach(containerName => {
      // patch volumeMount part to certain container
      const envSource = type === "configMap" ? 'configMapRef' : 'secretRef'
      ctx.mergeToYaml({
        name: workload,
        jsonPath: [
          `spec.template.spec.containers[?(@.name=="${containerName}")]`,
          `spec.template.spec.initContainers[?(@.name=="${containerName}")]`
        ],
        defer: true,
        content: {
          envFrom: [{
            [envSource]: {
              name: cfgName
            }
          }] as V1EnvFromSource[]
        }
      })
    })
  } else if (item.mount) {
    // patch volume part
    const volume: V1Volume = type === "configMap" ? {
      name: item.name,
      configMap: {
        name: cfgName
      }
    } : {
      name: item.name,
      secret: {
        secretName: cfgName
      }
    }
    ctx.mergeToYaml({
      name: workload,
      jsonPath: 'spec.template.spec',
      defer: true,
      content: {
        volumes: [volume]
      }
    })
    containers.forEach(containerName => {
      // patch volumeMount part to certain container
      ctx.mergeToYaml({
        name: workload,
        defer: true,
        jsonPath: [
          `spec.template.spec.containers[?(@.name=="${containerName}")]`,
          `spec.template.spec.initContainers[?(@.name=="${containerName}")]`
        ],
        content: {
          volumeMounts: [{
            name: item.name,
            mountPath: item.mount
          }] as V1VolumeMount[]
        }
      })
    })
  }
}

export const randomString = (length: number, chars: string): string => {
  const charsLength = chars.length
  const randomBytes = crypto.randomBytes(length)
  const result = new Array(length)
  let cursor = 0
  for (let i = 0; i < length; i++) {
    cursor += randomBytes[i]
    result[i] = chars[cursor % charsLength]
  }
  return result.join('')
}

export const randomAlphabet = (length: number): string => {
  return randomString(length, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
}

export const randomNumeric = (length: number): string => {
  return randomString(length, "0123456789")
}

export const randomAlphabetNumeric = (length: number): string => {
  return randomString(length, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
}

export const randomHex = (length: number): string => {
  return randomString(length, "0123456789abcdef")
}